package com.lambkit.module.upms.auth.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import com.lambkit.auth.AuthSession;
import com.lambkit.auth.AuthUser;
import com.lambkit.auth.annotation.LambkitAuth;
import com.lambkit.auth.service.AuthDataService;
import com.lambkit.auth.service.AuthSessionService;
import com.lambkit.core.Attr;
import com.lambkit.core.Lambkit;
import com.lambkit.core.http.IController;
import com.lambkit.module.upms.UpmsConsts;
import com.lambkit.module.upms.UpmsKernel;
import com.lambkit.module.upms.auth.cache.UpmsCache;
import com.lambkit.module.upms.row.UpmsUser;
import com.lambkit.web.HttpContextHolder;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author yangyong(孤竹行)
 */
public abstract class AbstractUpmsKernel implements UpmsKernel {
    @Override
    public UpmsCache getCache() {
        return Lambkit.get(UpmsCache.class);
    }

    @Override
    public String getSessionId() {
        AuthSessionService sessionService = Lambkit.get(AuthSessionService.class, UpmsSessionService.class);
        String sessionId = sessionService.getId(HttpContextHolder.get().getRequest());
        return sessionId;
    }

    @Override
    public Map getActiveSessions(int offset, int limit) {
        Map sessions = new HashMap();
        // 获取在线会话总数
        long total = getCache().llen(UpmsConsts.LAMBKIT_UPMS_SERVER_SESSION_IDS);
        // 获取当前页会话详情
        List<String> ids = getCache().lrange(UpmsConsts.LAMBKIT_UPMS_SERVER_SESSION_IDS, offset, (offset + limit - 1));
        if(ids==null || ids.size()==0) {
            return sessions;
        }
        List<Attr> rows = CollUtil.newArrayList();
        for (String id : ids) {
            String code = getCache().get(UpmsConsts.LAMBKIT_UPMS_SERVER_SESSION_ID + "_" + id);
            // 过滤redis过期session
            if (null == code) {
                getCache().lrem(UpmsConsts.LAMBKIT_UPMS_SERVER_SESSION_IDS, 1, id);
                total = total - 1;
                continue;
            }
            AuthUser authUser = getCache().getAuthUser(code);
            AuthSession authSession = (AuthSession) HttpContextHolder.get().getRequest().getAttribute("authSession");
            Attr data = Attr.by("id", id);
            data.set("userAgent", authSession.getUserAgent());
            data.set("status", 1);
            data.set("userBean", authUser.getUserBean());
            data.set("startTimestamp", DateUtil.current());
            data.set("lastAccessTime", authSession.getLastAccessTime());
            data.set("host", authSession.getHost());
            data.set("expired", authSession.isExpired());
            data.set("userName", authUser.getUserName());
            data.set("code", code);
            rows.add(data);
            //rows.add(SerializableUtil.deserialize(session));
        }
        sessions.put("total", total);
        sessions.put("rows", rows);
        return sessions;
    }

    @Override
    public int forceout(String ids) {
        String[] sessionIds = ids.split(",");
        for (String sessionId : sessionIds) {
            getCache().logout(sessionId);
        }
        return sessionIds.length;
    }

    @Override
    public AuthUser getAuth() {
        return getAuthKernelService().getAuth(getSessionId());
    }
    @Override
    public String getAuthId() {
        return getAuthKernelService().authenticate(getSessionId());
    }

    protected AuthDataService getAuthDataService() {
        return Lambkit.get(AuthDataService.class, UpmsDataService.class);
    }

    @Override
    public boolean hasAnyRoles(UpmsUser upmsUser, String aSuper) {
        return getAuthDataService().hasAnyRoles(upmsUser.getUserId(), aSuper);
    }

    @Override
    public boolean hasRule(UpmsUser upmsUser, Long permissionId) {
        return getAuthDataService().hasRule(upmsUser.getUserId(), permissionId);
    }


    public abstract int validation(Class clazz, Method method, IController controller, UpmsUser upmsUser);

    /*public int validation(Invocation invocation, UpmsUser upmsUser) {
        Controller controller = invocation.getController();
        Method method = invocation.getMethod();
        Class clazz = invocation.getTarget().getClass();
        int code = handleMethod(method, controller, upmsUser);
        if(code!=200) {
            return code;
        }
        code = handleClass(clazz, controller, upmsUser);
        if(code!=200) {
            return code;
        }
        code = validation(clazz, method, controller, upmsUser);
        return code;
    }*/

    /**
     * 权限角色判断机制
     *
     * @param method
     * @param controller
     * @return
     */
    private int handleMethod(Method method, IController controller, UpmsUser upmsUser) {
        // 判断是否有这个注解
        if (method.isAnnotationPresent(LambkitAuth.class)) {
            LambkitAuth lambkitAuth = method.getAnnotation(LambkitAuth.class);
            return handleLambkitAuth(lambkitAuth, upmsUser);
        }
        // 没有这个注解直接放行
        return 1;
    }

    /**
     * 类级别判断机制
     *
     * @param clazz
     * @param controller
     * @return
     */
    private int handleClass(Class clazz, IController controller, UpmsUser upmsUser) {
        // 方法上如果有了以方法上的为准
        if (clazz.isAnnotationPresent(LambkitAuth.class)) {
            LambkitAuth lambkitAuth = (LambkitAuth) clazz.getAnnotation(LambkitAuth.class);
            return handleLambkitAuth(lambkitAuth, upmsUser);
        }
        // 没有这个注解直接放行
        return 1;
    }

    private int handleLambkitAuth(LambkitAuth lambkitAuth, UpmsUser upmsUser) {
        // 判断是否有这个注解
        if (lambkitAuth != null) {
            // 从请求头解析出user
            if(lambkitAuth.login()) {
                if(upmsUser==null) {
                    return 401;
                }
            }
            String[] handlerArray = lambkitAuth.withForces();
            if (handlerArray != null && handlerArray.length > 0) {
                return withForcesHandle(handlerArray, upmsUser);
            }
            handlerArray = lambkitAuth.withRoles();
            if (handlerArray != null && handlerArray.length > 0) {
                return withRolesHandle(handlerArray, upmsUser);
            }
            handlerArray = lambkitAuth.hasForces();
            if (handlerArray != null && handlerArray.length > 0) {
                return hasForcesHandle(handlerArray, upmsUser);
            }
            handlerArray = lambkitAuth.hasRoles();
            return hasRolesHandle(handlerArray, upmsUser);
        }
        // 没有这个注解直接放行
        return 1;
    }

    /**
     * 优先级第一--并关系权限处理方案
     *
     * @param withForces
     * @param me
     * @return
     */
    private int withForcesHandle(String[] withForces, UpmsUser me) {
        boolean flag = getAuthDataService().hasAllRules(me.getUserId(), ArrayUtil.join(withForces, ","));
        return flag ? 200 : 403;
    }

    /**
     * 优先级第二--并关系角色处理方案
     *
     * @param withRoles
     * @param me
     * @return
     */
    private int withRolesHandle(String[] withRoles, UpmsUser me) {
        boolean flag = getAuthDataService().hasAllRoles(me.getUserId(), ArrayUtil.join(withRoles, ","));
        return flag ? 200 : 403;
    }

    /**
     * 优先级第三--或关系权限处理方案
     *
     * @param hasForces
     * @param me
     * @return
     */
    private int hasForcesHandle(String[] hasForces, UpmsUser me) {
        boolean flag = getAuthDataService().hasAnyRules(me.getUserId(), ArrayUtil.join(hasForces, ","));
        return flag ? 200 : 403;
    }

    /**
     * 优先级第四--或关系角色处理方案
     *
     * @param hasRoles
     * @param me
     * @return
     */
    private int hasRolesHandle(String[] hasRoles, UpmsUser me) {
        boolean flag = getAuthDataService().hasAnyRoles(me.getUserId(), ArrayUtil.join(hasRoles, ","));
        return flag ? 200 : 403;
    }
}
